﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Fixx.Connector;
using System.Diagnostics;
using System.Text.RegularExpressions;
using Fixx.DTO;

namespace FixxVS
{
	public partial class ProjectList : UserControl
	{
		private Dictionary<string, int> _ProjectLookUpTable = new Dictionary<string, int>();
		private FixxPersistantStorage _Store { get; set; }

		public ProjectList()
		{
			InitializeComponent();
		}

		private bool HasValidStore()
		{
			return (this._Store != null && this._Store.Repository != null);
		}

		private void ProjectList_Load(object sender, EventArgs e)
		{
			this.ValidateStore();
			if (this.HasValidStore())
			{
				this._CreateColumns();

				this._SizeColumns();

				this._Load();
			}
		}

		private void btnRefresh_Click(object sender, EventArgs e)
		{
			this._Load();
		}

		private bool ValidateStore()
		{
			bool valid = false;
			var store = new FixxPersistantStorage();
			this.cmbProjects.Enabled = (store.Repository != null);
			this.txtQuery.Enabled = (store.Repository != null);
			this.btnSearch.Enabled = (store.Repository != null);
			this.lvIssues.Enabled = (store.Repository != null);
			this.lblLoading.Visible = false;
			if (store.Repository == null)
			{
				var settingsDialog = new Settings();
				settingsDialog.ShowDialog(this);
			}
			else
			{
				this._Store = store;
				valid = true;
			}
			return valid;

		}
		
		private void _Load()
		{
			this.lvIssues.Items.Clear();
			this.txtQuery.Clear();
			this.txtQuery.Enabled = false;
			this.cmbProjects.Enabled = false;
			this.btnSearch.Enabled = false;
			this.btnIssueActions.Enabled = false;
			this.btnFilter.Visible = false;
			this._SetBusy(true);
			this._Store.Repository.GetProjectsAsync(
				(projects) =>
				{
					this.SafeInvoke(() =>
						{
							this.cmbProjects.BeginUpdate();
							this.cmbProjects.Items.Clear();
							this._ProjectLookUpTable.Clear();
							projects.ToList<FixxProject>()
								.ForEach(p =>
								{
									this.cmbProjects.Items.Add(p.Name);
									this._ProjectLookUpTable.Add(p.Name, p.Id);

								}
							);
							this.cmbProjects.Enabled = true;
							this.cmbProjects.EndUpdate();
							this._SetBusy(false);
						});
				},
				(error) =>
				{
				}
			);
		}
	
		private void OpenSettingsDialog(Settings.OpenTo openTo)
		{
			var settingsDialog = new Settings(openTo);
			if (settingsDialog.ShowDialog(this) == DialogResult.OK)
			{
				if (this.ValidateStore())
				{
					if (settingsDialog.ConnectionSettingsChanged)
					{
						this._Load();
					}
					else
					{
						if (settingsDialog.ColumnSettingsChanged)
						{
							this._CreateColumns();
							this._SizeColumns();
						}
						this._searchIssues();
					}
				}

			}
		}
		
		private void btnSettings_Click(object sender, EventArgs e)
		{
			this.OpenSettingsDialog(Settings.OpenTo.ConnectionSettings);	
		}
		private void btnFilter_Click(object sender, EventArgs e)
		{
			this.OpenSettingsDialog(Settings.OpenTo.FilterSettings);
		}


		private void btnSearch_Click(object sender, EventArgs e)
		{
			this._searchIssues();
		}

		private void _searchIssues()
		{
			if (this.cmbProjects.SelectedItem == null ||
				string.IsNullOrEmpty(this.cmbProjects.SelectedItem.ToString()))
			{
				MessageBox.Show(this, "Please select a project before searching", "Search exception", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
				return;
			}
			this._SetBusy(true);
			
			var filter = new FixxIssueFilter();
			string selectedItemText = this.cmbProjects.SelectedItem.ToString();

			filter.ProjectId = this._ProjectLookUpTable[selectedItemText];

			if (!string.IsNullOrEmpty(this.txtQuery.Text))
				filter.Query = this.txtQuery.Text;

			filter.IncludeResolved = this._Store.Repository.FixxSettings.IncludeResolvedIssues;
			filter.IncludeClosed = this._Store.Repository.FixxSettings.IncludeClosedIssues;
			filter.OnlyAssignedToMe = this._Store.Repository.FixxSettings.OnlyIssuesAssignedToMe;

			var selectedIds = this.GetSelectedIssuesIds();

			this.lvIssues.Items.Clear();
			this.btnFilter.Visible = false;

			this._Store.Repository.GetIssuesAsync(filter,
				(issues, foundUnFiltered) =>
				{
					this.SafeInvoke(() =>
					{
						this.lvIssues.BeginUpdate();
						this.lvIssues.Items.Clear();
						this._AddIssuesToListView(issues);
						this._SizeColumns();
						if (this.lvIssues.ListViewItemSorter != null)
							this.lvIssues.Sort();
						this.lvIssues.EndUpdate();
						this.btnFilter.Text = "Found " + issues.Count().ToString() + " of " + foundUnFiltered.ToString();
						this.btnFilter.Visible = true;
						this._SetBusy(false);
					});
				},
				(error) =>
				{
				}
			);
		}

		private List<int> GetSelectedIssuesIds()
		{
			var list = new List<int>();

			if (this.lvIssues.Items.Count > 0)
			{
				var col = this.lvIssues.SelectedItems.OfType<ListViewItem>();
				col.ToList().ForEach(i => list.Add(int.Parse(i.Text)));
			}
			return list;
		}
		private List<FixxIssue> GetSelectedIssues()
		{
			if (this.cmbProjects.SelectedItem == null)
				return null;

			string selectedItemText = this.cmbProjects.SelectedItem.ToString();

			if (!this._ProjectLookUpTable.ContainsKey(selectedItemText))
				return null;

			int projectId = this._ProjectLookUpTable[selectedItemText];
			if (projectId <= 0)
				return null;

			var cache = this._Store.Repository.GetProjectCache(projectId);
			if (cache == null)
				return null;

			List<int> selectedIds = this.GetSelectedIssuesIds();
			var issues = from i in cache.Issues
						 where selectedIds.Contains(i.Id)
						 select i;
			return issues.ToList<FixxIssue>();
		}

		private void txtQuery_KeyUp(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Return)
				this._searchIssues();
		}

		private void lvIssues_ColumnClick(object sender, ColumnClickEventArgs e)
		{
			lvIssues.ToggleSort(e.Column);
		}

		private void cmbProjects_IndexChanged(object sender, EventArgs e)
		{
			this.lvIssues.Items.Clear();
			this.btnSearch.Enabled = true;
			this.txtQuery.Enabled = true;
			this.btnIssueActions.Enabled = true;
		}

		private void _AddIssuesToListView(IEnumerable<FixxIssue> issues)
		{
			var settings = ((FixxVSSettings)this._Store.Repository.FixxSettings);
			var config = settings.IssueListviewColumnConfig;
			var selectedIds = this.GetSelectedIssuesIds();
			issues.ToList<FixxIssue>()
				.ForEach(i =>
				{
					ListViewItem item = new ListViewItem(i.Id.ToString());
					foreach (var ci in config)
					{
						switch (ci.Key)
						{
							case FixxVSSettings.IssueListviewColumn.AffectedVersion:
								item.SubItems.Add((i.AffectedVersion == null) ? "" : i.AffectedVersion.Name);
								break;
							case FixxVSSettings.IssueListviewColumn.Area:
								item.SubItems.Add((i.Area == null) ? "" : i.Area.Name);
								break;
							case FixxVSSettings.IssueListviewColumn.AssignedTo:
								item.SubItems.Add((i.AssignedTo == null) ? "" : i.AssignedTo.Username);
								break;
							case FixxVSSettings.IssueListviewColumn.ClosedOn:
								item.SubItems.Add((!i.ClosedOn.HasValue) ? "" : 
									(settings.IsUsingPretyDateFormater)
									? i.ClosedOn.Value.ToPrettyString()
									: i.ClosedOn.Value.ToString());
								break;
							case FixxVSSettings.IssueListviewColumn.CreatedBy:
								item.SubItems.Add((i.CreatedBy == null) ? "" : i.CreatedBy.Username);
								break;
							case FixxVSSettings.IssueListviewColumn.Description:
								item.SubItems.Add((i.Description == null) ? "" : i.Description);
								break;
							case FixxVSSettings.IssueListviewColumn.DueOn:
								item.SubItems.Add((!i.DueOn.HasValue) ? "" : 
									(settings.IsUsingPretyDateFormater)
									? i.DueOn.Value.ToPrettyString()
									: i.DueOn.Value.ToString());
								break;
							case FixxVSSettings.IssueListviewColumn.EstimatedTime:
								item.SubItems.Add((i.EstimatedTime == null) ? "" : i.EstimatedTime.ToString());
								break;
							case FixxVSSettings.IssueListviewColumn.FixForVersion:
								item.SubItems.Add((i.FixForVersion == null) ? "" : i.FixForVersion.Name);
								break;
							case FixxVSSettings.IssueListviewColumn.IsClosed:
								item.SubItems.Add(i.IsClosed.ToString());
								break;
							case FixxVSSettings.IssueListviewColumn.IssueType:
								item.SubItems.Add((i.IssueType == null) ? "" : i.IssueType.Name);
								break;

							case FixxVSSettings.IssueListviewColumn.Priority:
								item.SubItems.Add((i.Priority == null) ? "" : i.Priority.Name);
								break;
							case FixxVSSettings.IssueListviewColumn.Resolution:
								item.SubItems.Add((i.Resolution == null) ? "" : i.Resolution.Name);
								break;
							case FixxVSSettings.IssueListviewColumn.ResolvedBy:
								item.SubItems.Add((i.ResolvedBy == null) ? "" : i.ResolvedBy.Username);
								break;
							case FixxVSSettings.IssueListviewColumn.ResolvedOn:

								item.SubItems.Add((!i.ResolvedOn.HasValue) ? "" : 
									(settings.IsUsingPretyDateFormater)
									? i.ResolvedOn.Value.ToPrettyString()
									: i.ResolvedOn.Value.ToString());
								break;
							case FixxVSSettings.IssueListviewColumn.Title:
								item.SubItems.Add((i.Title == null) ? "" : i.Title);
								break;
						}
					}
					if (selectedIds.Contains(i.Id))
					{
						item.Selected = true;
					}

					this.lvIssues.Items.Add(item);

				}
			);
		}

		private void _CreateColumns()
		{
			if (!this.HasValidStore())
				return;
			this.lvIssues.Columns.Clear();
			var config = ((FixxVSSettings)this._Store.Repository.FixxSettings).IssueListviewColumnConfig;
			List<ColumnHeader> columns = new List<ColumnHeader>()
			{
				new ColumnHeader() { Text = "#" }
			};
			foreach (var ci in config)
			{
				string text = Regex.Replace(ci.Key.ToString(),"(?!^)([A-Z])"," $1");
				columns.Add(new ColumnHeader() { Text = text } );
			}
			this.lvIssues.Columns.AddRange(columns.ToArray());
		}

		private void _SizeColumns()
		{
			if (!this.HasValidStore())
				return;

			lvIssues.BeginUpdate();
			var config = ((FixxVSSettings)this._Store.Repository.FixxSettings).IssueListviewColumnConfig;
			int index = 0;
			lvIssues.Columns[0].Width = -1;
			foreach (var ci in config)
			{
				lvIssues.Columns[++index].Width = (int)ci.Value;
			}
			lvIssues.EndUpdate();
		}

		private void lvIssues_SizeChanged(object sender, EventArgs e)
		{
			this._SizeColumns();
		}

		private void lvIssues_MouseDoubleClick(object sender, MouseEventArgs e)
		{
			this._EditSelectedIssue();
		}
		private void _SetBusy(bool busy)
		{
			this.lblLoading.Visible = busy;
			this.lblLoadingText.Visible = busy;
		}

		private void _EditSelectedIssue()
		{
			if (this.cmbProjects.SelectedItem == null
				|| this.lvIssues.SelectedItems.Count <= 0)
				return;

			int projectId = this._ProjectLookUpTable[this.cmbProjects.SelectedItem.ToString()];
			int issueId = int.Parse(this.lvIssues.SelectedItems[0].SubItems[0].Text);

			var dialog = new Issue(projectId, issueId);
			if (dialog.ShowDialog(this) == DialogResult.OK)
			{
				this._searchIssues();
			}
		}

		private void _AddIssue()
		{
			int projectId = this._ProjectLookUpTable[this.cmbProjects.SelectedItem.ToString()];

			var dialog = new Issue(projectId);
			if (dialog.ShowDialog(this) == DialogResult.OK)
			{
				this._searchIssues();
			}
		}

		private void addToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (this.cmbProjects.SelectedItem == null
				|| this.lvIssues.SelectedItems.Count <= 0)
				return;

			int projectId = this._ProjectLookUpTable[this.cmbProjects.SelectedItem.ToString()];
			int issueId = int.Parse(this.lvIssues.SelectedItems[0].SubItems[0].Text);

			var dialog = new Issue(projectId, issueId, true);
			if (dialog.ShowDialog(this) == DialogResult.OK)
			{
				this._searchIssues();
			}
		}

		private void btnIssueActions_Click(object sender, EventArgs e)
		{
			bool enable = this.lvIssues.SelectedItems.Count > 0;

			this.btnAddSimilar.Enabled = enable;
			this.btnEdit.Enabled = enable;
			this.btnMassOperations.Enabled = enable;
			
		}

		private void btnEdit_Click(object sender, EventArgs e)
		{
			this._EditSelectedIssue();
		}

		private void addNewIssueToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this._AddIssue();
		}

		private void resolveSelectedToolStripMenuItem_Click(object sender, EventArgs e)
		{
			var issues = this.GetSelectedIssues();
		}
	}
}
